package main

import (
	"fmt"
	"time"
)

/*
python java php 多线程编程，多进程编程，多线程编程和多进程编程的问题主要是消耗内存
协程：asyncio(python)  swolle(php)  netty(java)
协程：内存占用小，切换快，go语言只有协程---goroutine
注意：在协程是存在主死随从，即主协程挂掉，从协程也会挂掉，要保证所有从的执行完，主的才退出
*/

func asyncPrint() {
	time.Sleep(1 * time.Second)
	fmt.Println("slave1 goroutine")
}

func main() {

	/*
		一、如何启动单协程(go + 函数调用)
	*/
	// go关键字将函放到协程执行，异步执行 (主进程存活，协程才能正常使用)
	go asyncPrint()
	fmt.Println("main goroutine") //这个先打印，所以说是异步的，不然上面的函数先执行
	//
	//// 临时使用的匿名函数启动goroutine
	go func() {
		fmt.Println("goroutine slave2")
	}()
	time.Sleep(2 * time.Second) //保证主上面的从协程执行完成，主协程才退出

	/*
		二、启动多个协程
	*/
	//1、闭包 2、for循环的时候，每个变量会重复使用（坑）
	// 当我们进行第二轮的时候 i会变，由于是异步的过程，所以不能等到前面的i使用完，所以这里i值不能和非异步一样
	nums := []int{1, 2, 3}
	for _, i := range nums {
		go func() {
			fmt.Printf("%v\n", i)

		}()
		/*
			在上面的写法中会发现，打印的不按顺序，还可能出现重复值，这是因为上面出现了闭包，闭包变量值创建一次，存在多个协程并发问题，
			goroutine执行了闭包内的程序而闭包内直接引用了num变量，这个值并没有被保存到goroutine栈中，这样写及其容易窜数据，产生严重bug！
		*/
		// 解决goroutine在for的方案，推荐方案二
		// tmp := i 第一种解决i不能按顺序的做法，把i复制一份
		//第二种解决不能按顺序的做法：利用函数的值传递
		go func(j int) {
			fmt.Printf("goroutine slave%d\n", j)
		}(i)
		//第三种、不使用闭包

	}

	time.Sleep(1 * time.Second)
}
